package tr.com.netgis.web;

import java.io.StringReader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import tr.com.netgis.pojo.Message;
import tr.com.netgis.pojo.Message.Command;
import tr.com.netgis.util.NetMobileException;
import tr.com.netgis.util.Utility;

/**
 * 
 * @author NetGis
 * 
 */
public class SetLocationResponse {

	static String STATUS_SUCCESS = "wfs:SUCCESS";
	
	public static String TAG_NAME_INSERTED = "Inserted"; 
	public static String TAG_NAME_UPDATED = "Updated";
	public static String TAG_NAME_DELETED = "Deleted";
	public static String TAG_NAME_STATUS = "Status";
	public static String TAG_NAME_STATUS_SUCCESS = "SUCCESS";
	public static String TAG_NAME_IS_KNOWN_DEVICE = "IsUnknownDevice";
	public static String TAG_NAME_MESSAGES = "Messages";
	
	
	public static class TransactionResult {
		public String inserted = "";
		public String updated = "";
		public String deleted = "";
		public String status = "";
		
		public boolean isSuccessful(){
			return STATUS_SUCCESS.indexOf(this.status) >= 0;			
		}
		
		public TransactionResult(String inserted, String updated,
				String deleted, String status) {
			super();
			this.inserted = inserted;
			this.updated = updated;
			this.deleted = deleted;
			this.status = status;
		}
		
		public TransactionResult() {
			super();
		}
		
		public String toString () {
			return MessageFormat.format("Status: {3}\nInserted: {0}\nUpdated: {1}\nDeleted:{2}\n", 
					this.inserted,
					this.updated,
					this.deleted,
					this.status);
		}

	}	
	
	public static class TransactionResponse {
		public List<TransactionResult> results;

		public TransactionResponse(){
			results = new ArrayList<TransactionResult>();
		}
		public void add(TransactionResult result) {
			results.add(result);
		}
		
		public TransactionResult last(){
			return results.get(results.size() - 1);
		}		
		
		public String toString (){
			return results.toString();
		}
		
	}
	
	public static class PutInfoExResult {
		public List<TransactionResponse> responses;
		public PutInfoExResult (){
			responses = new ArrayList<TransactionResponse>();
		}
		public void add(TransactionResponse response) {
			responses.add(response);
		}
		public TransactionResponse last(){
			if (responses.size() == 0) {
				responses.add(new TransactionResponse());
			}
			return responses.get(responses.size() - 1);
		}
		public String toString(){
			return responses.toString();
		}		
	}
	
	
	public static class DataRetrievingServiceResult {
		public String isUnknownDevice = "";
		public List<Message> messages;
		
		public List<PutInfoExResult> putInfoExResults;
		public DataRetrievingServiceResult(){
			putInfoExResults = new ArrayList<PutInfoExResult>();
		}
		public void add(PutInfoExResult result) {
			putInfoExResults.add(result);
		}
		public PutInfoExResult last(){
			if (putInfoExResults.size() == 0) {
				putInfoExResults.add(new PutInfoExResult());
			}
			return putInfoExResults.get(putInfoExResults.size() - 1);
		}
		public Message lastMessage(){
			return messages.get(messages.size() - 1);
		}
		public String toString(){
			return MessageFormat.format("{0}\n[IsUnknownDevice: {1}, Messages:[{2}]]", 
					putInfoExResults.toString(),	
					isUnknownDevice, 
					messages);
		}
		public List<Message> getMessages (){
			return this.messages == null ? new ArrayList<Message>() : this.messages;
		}
	}
	
	public static class DataRetrievingServiceResults {
		public List<DataRetrievingServiceResult> results;
		public DataRetrievingServiceResults(){
			results = new ArrayList<DataRetrievingServiceResult>();
		}
		public void add(DataRetrievingServiceResult result) {
			results.add(result);
		}
		
		public DataRetrievingServiceResult last(){
			if (results.size() == 0)
				this.results.add(new DataRetrievingServiceResult());
			return results.get(results.size() -1);
		}
		
		public String toString(){
			StringBuilder result = new StringBuilder();
			for (DataRetrievingServiceResult dataRes : this.results) {
				for (PutInfoExResult putResult : dataRes.putInfoExResults) {
					for (TransactionResponse response : putResult.responses) {
						for (TransactionResult res : response.results) {
							result.append(res.toString());
						}
					}
				}
				result.append(TAG_NAME_IS_KNOWN_DEVICE + ": " + dataRes.isUnknownDevice + "\n");
				result.append(TAG_NAME_MESSAGES + ": " + dataRes.messages + "\n\n");
				
			}
			return result.toString();
		}
		
		public boolean isSuccessful(){
			for (DataRetrievingServiceResult dataRes : this.results) {
				for (PutInfoExResult putResult : dataRes.putInfoExResults) {
					for (TransactionResponse response : putResult.responses) {
						for (TransactionResult res : response.results) {
							if (!res.isSuccessful()) {
								return false;
							}
						}
					}
				}
			}
			
			return true;
		}
		
		public List<Message> getMessages (){
			List<Message> messages = new ArrayList<Message>();
			for (DataRetrievingServiceResult result : this.results) {
				messages.addAll(result.getMessages());
			}
			return messages;
		}
	}

	private String responseXml;
	private DataRetrievingServiceResults results;
		
	private String exceptionString;
	private Exception exception;
	
	public Exception getException (){
		return this.exception;
	}
	
	public SetLocationResponse(Exception e) {
		super();
		this.exception = e;
	}
	
	public SetLocationResponse(String responseXml) throws NetMobileException {
		super();
		/*
		String testMessage = "<Messages>" +
"<Message>" +
"<Sender>netadmin</Sender>" +
"<Time>13.01.2012 16:57:43</Time>" +
"<Type>Message</Type>" +
"<MessageHeader>messageheader1</MessageHeader >" +
"<MessageBody>MessageBodyyy1</MessageBody>" +
"<Command />" +
"<CommandParameter />" +
"</Message>" +
"<Message>" +
"<Sender>netadmin</Sender>" +
"<Time>13.01.2012 16:59:06</Time>" +
"<Type>Message</Type>" +
"<MessageHeader>messageheader2</MessageHeader >" +
"<MessageBody>MessageBodyyy2</MessageBody>" +
"<Command />" +
"<CommandParameter />" +
"</Message></Messages>" ;
		responseXml = responseXml.replaceAll("<Messages />", testMessage);
		*/
		this.responseXml = responseXml;
		parse();
		
	}
	
	public boolean isSuccessful (){
		return results != null ? results.isSuccessful() : false;
	}

	private void parse() throws NetMobileException {
		if (this.responseXml == null || "".equals(this.responseXml))
			return;
		try {
			XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
			factory.setNamespaceAware(true);
			XmlPullParser xpp = factory.newPullParser();

			xpp.setInput(new StringReader(responseXml));
			int eventType = xpp.getEventType();
			
			String tmpText = "";
			while (eventType != XmlPullParser.END_DOCUMENT) {
				if (eventType == XmlPullParser.START_DOCUMENT) {
				} else if (eventType == XmlPullParser.START_TAG) {
					tmpText = "";
					String name = xpp.getName();
					if ("DataRetrievingServiceResults".equals(name)) {
						this.results = new DataRetrievingServiceResults();
					} else if ("DataRetrievingServiceResult".equals(name)) {
						if (this.results == null)
							this.results = new DataRetrievingServiceResults();
						this.results.add(new DataRetrievingServiceResult());
					} else if ("PutInfoExResult".equals(name)) {
						this.results.last().add(new PutInfoExResult());
					} else if ("TransactionResponse".equals(name)) {
						this.results.last().last().add(new TransactionResponse());
					} else if ("TransactionResult".equals(name)) {
						this.results.last().last().last().add(new TransactionResult());
					}  else if (TAG_NAME_MESSAGES.equals(name)) {
						results.last().messages = new ArrayList<Message>();
					} else if ("Message".equals(name)) {
						results.last().messages.add(new Message());
					} else if (TAG_NAME_STATUS_SUCCESS.equals(name)) {
						this.results.last().last().last().last().status = TAG_NAME_STATUS_SUCCESS;
					} 
					
				} else if (eventType == XmlPullParser.END_TAG) {
					String name = xpp.getName();
					if (TAG_NAME_INSERTED.equals(name)) {
						this.results.last().last().last().last().inserted = tmpText;
					} else if (TAG_NAME_UPDATED.equals(name)) {
						this.results.last().last().last().last().updated = tmpText;
					} else if (TAG_NAME_DELETED.equals(name)) {
						this.results.last().last().last().last().deleted = tmpText;
					} else if (TAG_NAME_IS_KNOWN_DEVICE.equals(name)) {
						this.results.last().isUnknownDevice = tmpText;
					} else if ("Sender".equals(name)) {
						results.last().lastMessage().setSender(tmpText);
					} else if ("Time".equals(name)) {
						results.last().lastMessage().setTime(tmpText);
					} else if ("Type".equals(name)) {
						results.last().lastMessage().setType(tmpText);
					} else if ("MessageHeader".equals(name)) {
						results.last().lastMessage().setMessageHeader(tmpText);
					} else if ("MessageBody".equals(name)) {
						results.last().lastMessage().setMessageBody(tmpText);
					} else if ("Command".equals(name)) {
						results.last().lastMessage().setCommand(tmpText);
					} else if ("CommandParameter".equals(name)) {
						results.last().lastMessage().setCommandParameter(tmpText);
					}
				} else if (eventType == XmlPullParser.TEXT) {
					tmpText = xpp.getText();						
				}
				eventType = xpp.next();
			}
		} catch (Exception e) {
			throw new NetMobileException(e);
		}
	}

	public String getResponseXml() {
		return this.responseXml;
	}
	
	public String toString (){
		if (this.exceptionString != null || "".equals(this.exceptionString))
			return this.exceptionString;
		if (results != null)
			return this.results.toString();
		else 
			return "Result null";
	}

	public String getExceptionString() {
		return exceptionString;
	}

	public void setExceptionString(String exceptionString) {
		this.exceptionString = exceptionString;
	}
	
	public boolean hasException() {
		return Utility.isNotEmpty(this.exceptionString);
	}
	
	public List<Message> getMessages(){
		if (this.results != null) {
			return results.getMessages();
		}
		return new ArrayList<Message>();
	}
	
	public List<Command> getCommands(){
		List<Message> messages = new ArrayList<Message>();
		List<Command> result = new ArrayList<Message.Command>();
		if (this.results != null) {
			messages = results.getMessages();
		}
		if (messages == null || messages.size() == 0) {
			return result;
		} 
		
		for (Message message : messages) {
			Command command = message.getOutCommand();
			if (!(command == null || tr.com.netgis.util.Command.UNKNOWN.equals(command))) {
				result.add(command);
			}
		}
		return result;
	}
	
}
